`timescale 1ns / 1ps
`include "defines.vh"
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/06/11 22:39:31
// Design Name: 
// Module Name: ID_EX
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

//ID阶段到EX阶段锁存器
module ID_EX(
    input [0:0] clk,
    input [0:0] rst,

    input [0:0] Clear_Flag_Input,

    input [`Instruction_Bus] Instruction_Input,  //指令内容
    input [`Instruction_Addr_Bus] Instruction_Addr_Input, 

    input [6:0] opcode_Input, //操作码
    input [11:0] imm12_Input, //12位立即数
    input [19:0] imm20_Input,//20位立即数
    input [0:0] dis_Input,  //区分码
    input [2:0]func3_Input, //func3
    input [6:0] func7_Input,//func7

    input [`Reg_Data_Bus] Reg_1_Read_Data_Input,
    input [`Reg_Data_Bus] Reg_2_Read_Data_Input,

    input [0:0] Write_Reg_Flag_Input,  //寄存器写标志
    input [`Reg_Addr_Bus] Write_Reg_Addr_Input,  //寄存器写地址

    // 接收读取的寄存器的地址
    input [`Reg_Addr_Bus] Reg_1_Read_Addr_Input,
    input [`Reg_Addr_Bus] Reg_2_Read_Addr_Input,

    output [`Instruction_Bus] Instruction_Output,  //指令内容
    output [`Instruction_Addr_Bus] Instruction_Addr_Output, 

    output [6:0] opcode_Output, //操作码
    output [11:0] imm12_Output, //12位立即数
    output [19:0] imm20_Output,//20位立即数
    output [0:0] dis_Output,  //区分码
    output [2:0]func3_Output, //func3
    output [6:0] func7_Output,//func7

    output [`Reg_Data_Bus] Reg_1_Read_Data_Output,
    output [`Reg_Data_Bus] Reg_2_Read_Data_Output,


    output [0:0] Write_Reg_Flag_Output,  //寄存器写标志
    output [`Reg_Addr_Bus] Write_Reg_Addr_Output,  //寄存器写地址

    // 输出读取的寄存器的地址
    output [`Reg_Addr_Bus] Reg_1_Read_Addr_Output,
    output [`Reg_Addr_Bus] Reg_2_Read_Addr_Output,


    // 数据冒险 前递操作
    // 接收由EX_MEM发来的前递ALU结果
    input [0:0] Write_Reg_Flag_Forward_Input,
    input [`Reg_Addr_Bus] Write_Reg_Addr_Forward_Input,
    input [`ALU_Parameter_BUS] ALU_Result_Forward_Input,

    // 接收由MEM_WB发来的前递Regs写结果
    input [0:0] Write_Reg_Flag_Forward_Input2,
    input [`Reg_Addr_Bus] Write_Reg_Addr_Forward_Input2,
    input [`Reg_Data_Bus] Write_Reg_Data_Forward_Input2






    );
    
    wire [`Reg_Data_Bus] Reg_1_Read_Data_Input_or_forward;
    wire [`Reg_Data_Bus] Reg_2_Read_Data_Input_or_forward;

    wire [`Reg_Data_Bus] Reg_1_Read_Data_EX_MEM_Forward;
    wire [`Reg_Data_Bus] Reg_2_Read_Data_EX_MEM_Forward;

    wire [`Reg_Data_Bus] Reg_1_Read_Data_MEM_WB_Forward;
    wire [`Reg_Data_Bus] Reg_2_Read_Data_MEM_WB_Forward;




    // 前递操作: 判断上一个指令的前递写地址和当前指令的读地址是否相同且写入标志位为真，相同则使用前递地址

    // EX_MEM前递
    assign Reg_1_Read_Data_EX_MEM_Forward = ((Write_Reg_Addr_Forward_Input == Reg_1_Read_Addr_Input)&&(Write_Reg_Flag_Forward_Input == `Write_Reg_Flag_Enabled)) ?  ALU_Result_Forward_Input : Reg_1_Read_Data_Input;
    assign Reg_2_Read_Data_EX_MEM_Forward = ((Write_Reg_Addr_Forward_Input == Reg_2_Read_Addr_Input)&&(Write_Reg_Flag_Forward_Input == `Write_Reg_Flag_Enabled)) ?  ALU_Result_Forward_Input : Reg_2_Read_Data_Input;

    assign Reg_1_Read_Data_MEM_WB_Forward = ((Write_Reg_Addr_Forward_Input2 == Reg_1_Read_Addr_Input)&&(Write_Reg_Flag_Forward_Input2 == `Write_Reg_Flag_Enabled)) ? Write_Reg_Data_Forward_Input2 : Reg_1_Read_Data_Input;
    assign Reg_2_Read_Data_MEM_WB_Forward = ((Write_Reg_Addr_Forward_Input2 == Reg_2_Read_Addr_Input)&&(Write_Reg_Flag_Forward_Input2 == `Write_Reg_Flag_Enabled)) ? Write_Reg_Data_Forward_Input2 : Reg_2_Read_Data_Input;

    // 两种冒险同时发生，优先处理EX_MEM冒险

    // 若EX_MEM冒险发生或都发生：直接给EX_MEM的值，若MEM_WD冒险发生或都不发生，给MEM_WB的值
    assign Reg_1_Read_Data_Input_or_forward = (Write_Reg_Addr_Forward_Input == Reg_1_Read_Addr_Input) ? Reg_1_Read_Data_EX_MEM_Forward : Reg_1_Read_Data_MEM_WB_Forward;
    assign Reg_2_Read_Data_Input_or_forward = (Write_Reg_Addr_Forward_Input == Reg_2_Read_Addr_Input) ? Reg_2_Read_Data_EX_MEM_Forward : Reg_2_Read_Data_MEM_WB_Forward;




    Latch #(32) Latch_ID_EX_Instruction(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value(`INST_NOP), 
    .Write_Input(Instruction_Input), .Read_Output(Instruction_Output));

    Latch #(32) Latch_ID_EX_Instruction_Addr(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value(`Zero32), 
    .Write_Input(Instruction_Addr_Input), .Read_Output(Instruction_Addr_Output));


    Latch #(7) Latch_ID_EX_opcode(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value({7{1'b0}}), 
    .Write_Input(opcode_Input), .Read_Output(opcode_Output));

    Latch #(12) Latch_ID_EX_imm12(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value({12{1'b0}}), 
    .Write_Input(imm12_Input), .Read_Output(imm12_Output));

    Latch #(20) Latch_ID_EX_imm20(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value({20{1'b0}}), 
    .Write_Input(imm20_Input), .Read_Output(imm20_Output));

    Latch #(1) Latch_ID_EX_dis(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value({1{1'b0}}), 
    .Write_Input(dis_Input), .Read_Output(dis_Output));

    Latch #(3) Latch_ID_EX_func3(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value({3{1'b0}}), 
    .Write_Input(func3_Input), .Read_Output(func3_Output));

    Latch #(7) Latch_ID_EX_func7(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value({3{1'b0}}), 
    .Write_Input(func7_Input), .Read_Output(func7_Output));

    Latch #(32) Latch_ID_EX_Reg_1_Read_Data(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value(`Regs_Rst), 
    .Write_Input(Reg_1_Read_Data_Input_or_forward), .Read_Output(Reg_1_Read_Data_Output));

    Latch #(32) Latch_ID_EX_Reg_2_Read_Data(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value(`Regs_Rst), 
    .Write_Input(Reg_2_Read_Data_Input_or_forward), .Read_Output(Reg_2_Read_Data_Output));

    Latch #(1) Latch_ID_EX_Write_Reg_Flag(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value(`Write_Reg_Flag_Disabled), 
    .Write_Input(Write_Reg_Flag_Input), .Read_Output(Write_Reg_Flag_Output));

    Latch #(5) Latch_ID_EX_Write_Reg_Addr(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value(`Regs_Addr_Rst), 
    .Write_Input(Write_Reg_Addr_Input), .Read_Output(Write_Reg_Addr_Output));

    Latch #(5) Latch_ID_EX_Reg_1_Read_Addr(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value(`Regs_Addr_Rst), 
    .Write_Input(Reg_1_Read_Addr_Input), .Read_Output(Reg_1_Read_Addr_Output));

    Latch #(5) Latch_ID_EX_Reg_2_Read_Addr(.clk(clk), .rst(rst), .Clear_Flag(Clear_Flag_Input), .Default_Value(`Regs_Addr_Rst), 
    .Write_Input(Reg_2_Read_Addr_Input), .Read_Output(Reg_2_Read_Addr_Output));





    always @(posedge clk) begin
        $display($time,"=================  ID_EX:  Instruction:%d,opcode:%d,imm12:%d,imm20:%d,dis:%d,func3:%d,func7:%d,Reg_1_Read:%d,Reg_2_Read:%d,Write_Reg_Flag:%d,Write_Reg_Addr:%d ",Instruction_Output,opcode_Output,$signed(imm12_Output),$signed(imm20_Output),dis_Output,func3_Output,func7_Output,$signed(Reg_1_Read_Data_Output),$signed(Reg_2_Read_Data_Output),Write_Reg_Flag_Output,Write_Reg_Addr_Output);
    end




endmodule
